/**
 *  test_sem.c - Test codes for semaphore and its functions.
 *               It runs on Windows or Linux.
 *
 *  Copyright (C) 2008  ZhangHu
 *  All rights reserved.
 *  E-MAIL: anmnmnly@gmail.com
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <stdio.h>
#include "test_sem.h"
#include "include/list.h"
#include "sem_stubs.h"
#include "kernel/list.c"
#include "kernel/sem.c"


static void test_semInit_0(void) {
    /* Initializing argument 1 (SemID) */
    uword_t _SemID = 0;

    /* Initializing argument 2 (InitCnt) */
    uword_t _InitCnt = 0;

   /* Tested function call */
    sem_t *_result = semInit(_SemID, _InitCnt);

    CU_ASSERT_PTR_NOT_NULL(_result);
}



static void test_semInit_1(void) {
    /* Initializing argument 1 (SemID) */
    uword_t _SemID = ~0;

    /* Initializing argument 2 (InitCnt) */
    uword_t _InitCnt = 0;

    /* Tested function call */
    sem_t *_result  = semInit(_SemID, _InitCnt);

    CU_ASSERT_PTR_NOT_NULL(_result);
}



static void test_semInit_2(void) {
    /* Initializing argument 1 (SemID) */
    uword_t _SemID  = 0;

    /* Initializing argument 2 (InitCnt) */
    uword_t _InitCnt = 10;

    /* Tested function call */
    sem_t *_result = semInit(_SemID, _InitCnt);

    CU_ASSERT_PTR_NULL(_result);
}



static void test_semInitMutex_0(void) {
    /* Initializing argument 1 (SemID) */
    uword_t _SemID = 1000;

    /* Tested function call */
    sem_t *_result = semInitMutex(_SemID);

    CU_ASSERT_PTR_NOT_NULL(_result);
    CU_ASSERT_EQUAL(_result->sem_cnt, 1);
}



static void test_semInitMutex_1(void) {
    list_t *list = NULL;
    int cnt = 0;

    /* Initializing argument 1 (SemID) */
    uword_t _SemID = 1000;

    /* Tested function call */
    sem_t *_result = semInitMutex(_SemID);

    CU_ASSERT_PTR_NULL(_result);

    // check all semphores created.
    list = sem_head.next;
    CU_ASSERT_PTR_NOT_EQUAL(list, &sem_head);

    do {
        cnt++;
        list = list->next;
    } while(list != sem_head.next);
printf("%d\n", cnt);
    CU_ASSERT_EQUAL(cnt, 3);
}



static void test_semDel_0(void) {
    semDel(0, NULL);
    semDel(~0, NULL);
    semDel(100, NULL);
    semDel(1000, NULL);
    semDel(10000, NULL);

    CU_ASSERT_PTR_EQUAL(sem_head.next, &sem_head);
    CU_ASSERT_PTR_EQUAL(sem_head.prev, &sem_head);
}



static void test_semGain_0(void) {
    sem_t *psem = semInit(1000, 2);
    list_t *list;

    semGain(1000, psem);
    CU_ASSERT_PTR_EQUAL(current()->sem_link.next, &psem->tcb_link);
    set_task(1);
    semGain(1000, psem);
    CU_ASSERT_PTR_EQUAL(current()->sem_link.next, &psem->tcb_link);
    CU_ASSERT_EQUAL(psem->sem_cnt, 0);

    set_task(2);
    semGain(1000, psem);
    CU_ASSERT_PTR_EQUAL(current()->sem_link.next, NULL);
    CU_ASSERT_PTR_EQUAL(psem->task_link[task_prio[2]].next, &current()->link);

    set_task(3);
    semGain(1000, psem);
    CU_ASSERT_PTR_EQUAL(current()->sem_link.next, NULL);
    CU_ASSERT_PTR_EQUAL(psem->task_link[task_prio[3]].next, &current()->link);

    set_task(4);
    semGain(1000, psem);
    CU_ASSERT_PTR_EQUAL(current()->sem_link.next, NULL);
    CU_ASSERT_PTR_EQUAL(psem->task_link[task_prio[4]].next, &current()->link);

    semDel(1000, psem);
    list = sleep.next;
    CU_ASSERT_PTR_EQUAL(list, &tcb_array[2].link);

    list = list->next;
    CU_ASSERT_PTR_EQUAL(list, &tcb_array[3].link);

    list = list->next;
    CU_ASSERT_PTR_EQUAL(list, &tcb_array[4].link);
}





static void test_semPost_0(void) {
    sem_t *psem = semInit(1000, 1);
    stubs_init();

    semGain(1000, psem);
    CU_ASSERT_EQUAL(psem->sem_cnt, 0);
    CU_ASSERT_EQUAL(psem->task_link[task_prio[0]].next,
                    &psem->task_link[task_prio[0]]);
    CU_ASSERT_PTR_EQUAL(current()->sem_link.next, &psem->tcb_link);

    semPost(1000, psem);
    CU_ASSERT_EQUAL(psem->sem_cnt, 1);
    CU_ASSERT_PTR_EQUAL(current()->sem_link.next, NULL);

    semGain(1000, psem);

    set_task(3);
    semGain(1000, psem);

    set_task(1);
    semGain(1000, psem);

    set_task(2);
    semGain(1000, psem);

    set_task(4);
    semGain(1000, psem);

    set_task(0);
    semPost(1000, psem);

    set_task(1);
    CU_ASSERT_PTR_EQUAL(current()->sem_link.next, &psem->tcb_link);

    CU_ASSERT_PTR_EQUAL(psem->task_link[task_prio[2]].next,
                        &tcb_array[2].link);
    CU_ASSERT_PTR_EQUAL(psem->task_link[task_prio[3]].next,
                        &tcb_array[3].link);
    CU_ASSERT_PTR_EQUAL(psem->task_link[task_prio[4]].next,
                        &tcb_array[4].link);
}



int test_sem_init(void) {
    initsem();
    stubs_init();
    printf("Semaphore test ...\n\n");
    return 0;
}



int test_sem_clean(void) {
    printf("Semphore test is over!\n\n");
    return 0;
}



CU_TestInfo test_sem_cases[] = {
    {"test_semInit_0", test_semInit_0},
    {"test_semInit_1", test_semInit_1},
    {"test_semInit_2", test_semInit_2},
    {"test_semInitMutex_0", test_semInitMutex_0},
    {"test_semInitMutex_1", test_semInitMutex_1},
    {"test_semDel_0", test_semDel_0},
    {"test_semGain_0", test_semGain_0},
    {"test_semPost_0", test_semPost_0},
    CU_TEST_INFO_NULL
};
